package com.baymax.controller;

import cn.hutool.core.util.StrUtil;
import com.baymax.common.BaseController;
import com.baymax.common.R;
import com.baymax.entity.dto.LoginDTO;
import com.baymax.entity.vo.SysUserVO;
import com.baymax.security.entity.OnlineUser;
import com.baymax.security.entity.SecurityUser;
import com.baymax.security.entity.TokenUserInfo;
import com.baymax.security.properties.SecurityProperties;
import com.baymax.utils.JwtUtil;
import com.baymax.utils.RedisUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.TimeUnit;

/**
 * 用户认证
 *
 * @Author: baymax
 * @CreateTime: 2023/3/28 22:34
 * @Version: 1.0
 */
@RestController
@RequestMapping(value = "/auth")
@RequiredArgsConstructor
public class AuthenticationController extends BaseController {

    private final AuthenticationManager authenticationManager;
    private final SecurityProperties securityProperties;
    private final RedisUtil redisUtil;

    @PostMapping(value = "/login")
    public R login(LoginDTO loginDTO) {
        if (StrUtil.isBlank(loginDTO.getUsername()) || StrUtil.isBlank(loginDTO.getPassword())) {
            throw new RuntimeException("用户名或密码不能为空");
        }
        Authentication authentication = null;
        try {
            // 用户名密码验证
            authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(loginDTO.getUsername(), loginDTO.getPassword()));
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
        return success(buildAuthenticationInfo((SecurityUser) authentication.getPrincipal()));
    }

    /**
     * 构建用户认证信息
     */
    private TokenUserInfo buildAuthenticationInfo(SecurityUser securityUser) {
        TokenUserInfo userInfo = new TokenUserInfo();
        String token = JwtUtil.createToken(securityUser.getUserId());
        String refreshToken = JwtUtil.createToken(securityUser.getUserId());
        userInfo.setToken(securityProperties.getTokenHeader() + token);
        userInfo.setRefreshToken(securityProperties.getTokenHeader() + refreshToken);
        userInfo.setUserId(securityUser.getUserId());
        userInfo.setUsername(securityUser.getUsername());
        // 是否允许重复登录
        if (securityProperties.getSingle()) {
            redisUtil.deletePrefixKey(securityProperties.getOnlineKey() + securityUser.getUserId() + StrUtil.COLON);
        }
        // 缓存在线用户
        OnlineUser onlineUser = new OnlineUser();
        onlineUser.setToken(securityProperties.getTokenHeader() + token);
        onlineUser.setRefreshToken(securityProperties.getTokenHeader() + refreshToken);
        onlineUser.setSysUserVO(new SysUserVO(securityUser.getUserId(), securityUser.getUsername()));
        onlineUser.setRoleVOList(securityUser.getRoleVOList());
        onlineUser.setMenuPermissionList(securityUser.getMenuPermissionList());
        String onlineKey = JwtUtil.buildOnlineUserKey(securityProperties.getOnlineKey(), securityUser.getUserId(), token);
        redisUtil.set(onlineKey, onlineUser, securityProperties.getExpirationTime(), TimeUnit.SECONDS);
        return userInfo;
    }

}
